{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "7f13fde9-bd57-4bfe-afa5-18a7e9ad540e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import torch\n",
    "import jieba\n",
    "import pandas as pd\n",
    "\n",
    "data_dir = 'https://mirror.coggle.club/dataset/coggle-competition/'\n",
    "train_data = pd.read_csv(data_dir + 'intent-classify/train.csv', sep='\\t', header=None)\n",
    "test_data = pd.read_csv(data_dir + 'intent-classify/test.csv', sep='\\t', header=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "721b91d1-387c-4cb4-ac0f-fba3dce3ebf3",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>还有双鸭山到淮阴的汽车票吗13号的</td>\n",
       "      <td>Travel-Query</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>从这里怎么回家</td>\n",
       "      <td>Travel-Query</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>随便播放一首专辑阁楼里的佛里的歌</td>\n",
       "      <td>Music-Play</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>给看一下墓王之王嘛</td>\n",
       "      <td>FilmTele-Play</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>我想看挑战两把s686打突变团竞的游戏视频</td>\n",
       "      <td>Video-Play</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                       0              1\n",
       "0      还有双鸭山到淮阴的汽车票吗13号的   Travel-Query\n",
       "1                从这里怎么回家   Travel-Query\n",
       "2       随便播放一首专辑阁楼里的佛里的歌     Music-Play\n",
       "3              给看一下墓王之王嘛  FilmTele-Play\n",
       "4  我想看挑战两把s686打突变团竞的游戏视频     Video-Play"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "d74905c7-a829-4ffa-8fe8-7894bb2fd393",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(12100, 2)"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "8b4941f7-fb89-41d8-9624-5c0b4bf93451",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_data[1], lbl = pd.factorize(train_data[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "909bf28e-40d7-40a4-abec-76784e3a4353",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def coustom_data_iter(texts, labels):\n",
    "    for x, y in zip(texts, labels):\n",
    "        yield x, y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "1db0d703-b697-4bfc-ab77-bbd2797eea14",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_iter = coustom_data_iter(train_data[0].values[:], train_data[1].values[:])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "99a3b2f7-b6a9-41c5-8d33-e62db5cba47e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('还有双鸭山到淮阴的汽车票吗13号的', 0)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(train_iter)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "c7873963-2dc6-4074-97b7-23f458208f2d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from torchtext.data.utils import get_tokenizer\n",
    "from torchtext.vocab import build_vocab_from_iterator\n",
    "\n",
    "tokenizer = jieba.lcut\n",
    "\n",
    "def yield_tokens(data_iter):\n",
    "    for text, _ in data_iter:\n",
    "        yield tokenizer(text)\n",
    "\n",
    "vocab = build_vocab_from_iterator(yield_tokens(train_iter), specials=[\"<unk>\"])\n",
    "vocab.set_default_index(vocab[\"<unk>\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "d358804c-9e82-470b-9b9d-eea3f62a84a6",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[262, 7012, 41, 771]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vocab(['我们', '存在', '今天', '你好'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "0fb3ca72-eb95-4206-ac14-c6618b6fe49f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def text_pipeline(x): return vocab(tokenizer(x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "5429df31-bade-48b4-a46d-a351453ec1dd",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[262, 41, 32, 663, 1045, 0]"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text_pipeline('我们今天在这里学习323232dsdsd')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "8e56016e-8d7a-4eb4-bb05-44785f09b0a7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from torch.utils.data import DataLoader\n",
    "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "def collate_batch(batch):\n",
    "    label_list, text_list, offsets = [], [], [0]\n",
    "    for (_text, _label) in batch:\n",
    "        label_list.append(_label)\n",
    "        processed_text = torch.tensor(text_pipeline(_text), dtype=torch.int64)\n",
    "        text_list.append(processed_text)\n",
    "        offsets.append(processed_text.size(0))\n",
    "    \n",
    "    label_list = torch.tensor(label_list, dtype=torch.int64)\n",
    "    offsets = torch.tensor(offsets[:-1]).cumsum(dim=0)\n",
    "    text_list = torch.cat(text_list)\n",
    "    return label_list.to(device), text_list.to(device), offsets.to(device)\n",
    "\n",
    "dataloader = DataLoader(train_iter, batch_size=8, shuffle=False, collate_fn=collate_batch)"
   ]
  },
  {
   "attachments": {
    "b547eb4e-7ad5-434f-a384-a476283aea49.png": {
     "image/png": "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OvuzzjrryBprrOG9HjlypPTs2dNb/lX3sTLXarqWNGncxFvHHwQQQACBqgL0JFc1YQ0CCCDgCdi44UsuuURatmwpd911l1xx+RWy8cYbe0Hun0v/9PZ5//335bjux3nrbZsFsJaGDRsmu+++u7e+devW3jr7c8opp8iLL77ovR4xYoRsv/320qVLFxk6dKh069ZNOnTo4C3feeedXjB+7LHHyo6ddxR7XrRokfz555/Sr18/2WKLLby8+/bt6+VlAfI555wjm2yyibd+8ODB3vr33ntPTj311HhQfcThR3hlPvP0M952/iCAAAIIVCOg/wiQEEAAAQRSCFxzzTXl2itcPm78OG/rytLSch3XW64fp+Ua0JavWrXKW7/kzyXeOls/d+7ceE6ff/65t36ttdaKr7OFEc+P8Nafcuqp3nodflH+0EMPlWuw7K1v06ZN+ZZbbll+1VVXlWtwHM/76quvjudz/fXXe+s1iI+vswW3//33319pvQbf3v4TJ02stJ4XCCCAAAKpBehJrubLA6sRQKC4BT744AO56aabxC5269yps4fRqGFDufnmm71hD++8845YT7AlG7aggbC3nPinVatWiS+rXW7SpImceeaZcswxx3j72PCMsWPHemVZGW6oxC233CK//fabt0/z5s1T5rfNNtukXM9KBBBAAIG6CRAk182LvRFAoEgERo8e7Z2pDX9ITBac9ujRw1v1wgsvxDfZOGRLNr44ObltyeuTX1uwbOmvf/2rN2zCli2/Pn372KI3ZMKmcbPkynHP3sqEP9WtT9iFRQQQQACBGgQIkmvAYRMCCBSvwNtvv+2d/Pob+BfcJUrocAjv5bfffpu4OmfLbdu0jfdUz5w1M2flkDECCCCAQIUAQXKFBUsIIIBAXMANa/h59s/xdW5hs8028xYTL8hz21I9u5koUm1Ld91WW23l7WoX5qWTdIRdOruxDwIIIIBANQIEydXAsBoBBIpbwGadsGSzQyQnm2XC0t577x3ftNpqq3nLejFffJ1bSLXObUv1nCrAnTNnjrfrttts6z031PHRlkpLS73n5D/ZCMyT8+Q1AgggUEwCBMnF1NqcKwIIpC3gLpZ744035Icffqh03Did49jSgQceGF/vepVnzZoVX+eGbNh8yYmBb6OG/hT1P8X21RkxZOXKlfHjXC+2WzFt2jRvbuPDDjss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GMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8CGMn+8qV0CEAAAhCAAAQgAIEAEsBIDqDSEBkCEIAABCAAAQhAwF8C/w944miC3k+v0wAAAABJRU5ErkJggg=="
    }
   },
   "cell_type": "markdown",
   "id": "16dc51e7-f78d-4c5d-a415-0dd8032cac30",
   "metadata": {},
   "source": [
    "![图片.png](attachment:b547eb4e-7ad5-434f-a384-a476283aea49.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "4ef75e48-bb8b-4262-98f7-376e7985b13a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "\n",
    "class TextClassificationModel(nn.Module):\n",
    "\n",
    "    def __init__(self, vocab_size, embed_dim, num_class):\n",
    "        super(TextClassificationModel, self).__init__()\n",
    "        self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=False)\n",
    "        self.fc = nn.Linear(embed_dim, num_class)\n",
    "        self.init_weights()\n",
    "\n",
    "    def init_weights(self):\n",
    "        initrange = 0.5\n",
    "        self.embedding.weight.data.uniform_(-initrange, initrange)\n",
    "        self.fc.weight.data.uniform_(-initrange, initrange)\n",
    "        self.fc.bias.data.zero_()\n",
    "\n",
    "    def forward(self, text, offsets):\n",
    "        embedded = self.embedding(text, offsets)\n",
    "        return self.fc(embedded)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "13fc7958-253c-4651-a179-1665648c8850",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "def train(dataloader):\n",
    "    model.train()\n",
    "    total_acc, total_count = 0, 0\n",
    "\n",
    "    for idx, (label, text, offsets) in enumerate(dataloader):\n",
    "        optimizer.zero_grad()\n",
    "        predicted_label = model(text, offsets)\n",
    "        loss = criterion(predicted_label, label)\n",
    "        loss.backward()\n",
    "        torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1)\n",
    "        optimizer.step()\n",
    "        total_acc += (predicted_label.argmax(1) == label).sum().item()\n",
    "        total_count += label.size(0)\n",
    "\n",
    "def evaluate(dataloader):\n",
    "    model.eval()\n",
    "    total_acc, total_count = 0, 0\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for idx, (label, text, offsets) in enumerate(dataloader):\n",
    "            predicted_label = model(text, offsets)\n",
    "            loss = criterion(predicted_label, label)\n",
    "            total_acc += (predicted_label.argmax(1) == label).sum().item()\n",
    "            total_count += label.size(0)\n",
    "    return total_acc/total_count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "5b791d42-ee8c-49a4-b952-aa5147ac6919",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from torch.utils.data.dataset import random_split\n",
    "from torchtext.data.functional import to_map_style_dataset\n",
    "\n",
    "train_iter = coustom_data_iter(train_data[0].values[:], train_data[1].values[:])\n",
    "train_dataset = to_map_style_dataset(train_iter)\n",
    "\n",
    "num_train = int(len(train_dataset) * 0.75)\n",
    "split_train_, split_valid_ = random_split(train_dataset, [num_train, len(train_dataset) - num_train])\n",
    "\n",
    "BATCH_SIZE = 16  # batch size for training\n",
    "train_dataloader = DataLoader(split_train_, batch_size=BATCH_SIZE,\n",
    "                              shuffle=True, collate_fn=collate_batch)\n",
    "valid_dataloader = DataLoader(split_valid_, batch_size=BATCH_SIZE,\n",
    "                              shuffle=True, collate_fn=collate_batch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "4fc20bb9-5d1e-46a7-84e4-1372b47dc45f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "num_class = len(lbl)\n",
    "vocab_size = len(vocab)\n",
    "emsize = 32\n",
    "model = TextClassificationModel(vocab_size, emsize, num_class).to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "a052aad2-656f-43a0-8cb0-4237d762935a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Hyperparameters\n",
    "EPOCHS = 20  # epoch\n",
    "LR = 5  # learning rate\n",
    "\n",
    "criterion = torch.nn.CrossEntropyLoss()\n",
    "optimizer = torch.optim.SGD(model.parameters(), lr=LR)\n",
    "scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.5)\n",
    "total_accu = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "20ffae17-be8c-4018-b152-26c250c7cd66",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "| end of epoch   1 | time:  2.11s | valid accuracy    0.829 \n",
      "| end of epoch   2 | time:  1.78s | valid accuracy    0.868 \n",
      "| end of epoch   3 | time:  1.82s | valid accuracy    0.882 \n",
      "| end of epoch   4 | time:  1.72s | valid accuracy    0.896 \n",
      "| end of epoch   5 | time:  1.80s | valid accuracy    0.889 \n",
      "| end of epoch   6 | time:  1.76s | valid accuracy    0.899 \n",
      "| end of epoch   7 | time:  1.75s | valid accuracy    0.901 \n",
      "| end of epoch   8 | time:  1.79s | valid accuracy    0.901 \n",
      "| end of epoch   9 | time:  1.63s | valid accuracy    0.903 \n",
      "| end of epoch  10 | time:  1.59s | valid accuracy    0.902 \n",
      "| end of epoch  11 | time:  1.77s | valid accuracy    0.903 \n",
      "| end of epoch  12 | time:  2.19s | valid accuracy    0.902 \n",
      "| end of epoch  13 | time:  2.00s | valid accuracy    0.902 \n",
      "| end of epoch  14 | time:  2.17s | valid accuracy    0.902 \n",
      "| end of epoch  15 | time:  2.32s | valid accuracy    0.902 \n",
      "| end of epoch  16 | time:  2.15s | valid accuracy    0.902 \n",
      "| end of epoch  17 | time:  2.30s | valid accuracy    0.902 \n",
      "| end of epoch  18 | time:  2.07s | valid accuracy    0.902 \n",
      "| end of epoch  19 | time:  2.36s | valid accuracy    0.902 \n",
      "| end of epoch  20 | time:  2.37s | valid accuracy    0.902 \n"
     ]
    }
   ],
   "source": [
    "for epoch in range(1, EPOCHS + 1):\n",
    "    epoch_start_time = time.time()\n",
    "    train(train_dataloader)\n",
    "    accu_val = evaluate(valid_dataloader)\n",
    "    \n",
    "    if total_accu is not None and total_accu > accu_val:\n",
    "        scheduler.step()\n",
    "    else:\n",
    "        total_accu = accu_val\n",
    "    \n",
    "    print('| end of epoch {:3d} | time: {:5.2f}s | '\n",
    "          'valid accuracy {:8.3f} '.format(epoch,\n",
    "                                           time.time() - epoch_start_time,\n",
    "                                           accu_val))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "0981d697-bc47-487c-90c1-8a741a577976",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_iter = coustom_data_iter(test_data[0].values[:], [0] * len(test_data))\n",
    "test_dataset = to_map_style_dataset(test_iter)\n",
    "test_dataloader = DataLoader(test_dataset, batch_size=BATCH_SIZE,\n",
    "                              shuffle=False, collate_fn=collate_batch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "32f6a161-af3b-496d-b653-5fa087ea30b6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def predict(dataloader):\n",
    "    model.eval()\n",
    "    \n",
    "    test_pred = []\n",
    "    with torch.no_grad():\n",
    "        for idx, (label, text, offsets) in enumerate(dataloader):\n",
    "            predicted_label = model(text, offsets).argmax(1)\n",
    "            test_pred += list(predicted_label.cpu().numpy())\n",
    "    return test_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "9363f7b0-caf0-4f99-97f6-47bfe27130cd",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_pred = predict(test_dataloader)\n",
    "test_pred = [lbl[x] for x in test_pred]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "b2c54c77-b6ae-4c5f-9baa-fbff5fec8354",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "pd.DataFrame({\n",
    "    'Id': range(1, len(test_pred) + 1),\n",
    "    'Category': test_pred,\n",
    "}).to_csv('nlp_submit.csv', index=None)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39942813-b17a-4062-ab37-9f78c3dd4bc5",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py3.11",
   "language": "python",
   "name": "py3.11"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
